// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 * Description: Export Pangea RDMA driver Vendor Hooks
 */

#ifdef CONFIG_VENDOR_PANGEA_RDMA_HOOKS

#define CREATE_TRACE_POINTS
#include <trace/hooks/rdma_pangea.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/sched/signal.h>
#include <linux/sched/mm.h>
#include <linux/export.h>
#include <linux/hugetlb.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/kmemleak.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_verbs.h>

#include "uverbs.h"

EXPORT_HOOK_SYMBOL_GPL(ofed_log_print_hook);
EXPORT_HOOK_SYMBOL_GPL(ofed_log_print_limit_hook);
EXPORT_HOOK_SYMBOL_GPL(ofed_monitor_exec_time_start);
EXPORT_HOOK_SYMBOL_GPL(ofed_monitor_exec_time_end);
#ifdef CONFIG_CENTRALIZED_STORAGE
EXPORT_HOOK_SYMBOL_GPL(ib_exec_umem_is_umm_addr);
EXPORT_HOOK_SYMBOL_GPL(ib_exec_umm_get_pyhs_addr);
EXPORT_HOOK_SYMBOL_GPL(ib_pangea_exec_get_dev_slot_id);
EXPORT_HOOK_SYMBOL_GPL(ib_pangea_exec_get_board_slot);
EXPORT_HOOK_SYMBOL_GPL(ib_device_exec_cmdq_timeout);
#endif

#ifdef CONFIG_CENTRALIZED_STORAGE
int ib_pangea_get_dev_slot_id(struct ib_device *device, unsigned int *slot_id)
{
	int i = -EINVAL;

	trace_ib_pangea_exec_get_dev_slot_id(device, slot_id, &i);
	return i;
}
EXPORT_SYMBOL(ib_pangea_get_dev_slot_id);

int ib_pangea_get_board_slot(unsigned int *slot)
{
	int i = -EINVAL;

	trace_ib_pangea_exec_get_board_slot(slot, &i);
	return i;
}
EXPORT_SYMBOL(ib_pangea_get_board_slot);

bool ib_umem_is_umm_addr(unsigned long addr)
{
	bool flag = false;

	trace_ib_exec_umem_is_umm_addr(addr, &flag);
	return flag;
}
EXPORT_SYMBOL(ib_umem_is_umm_addr);

phys_addr_t ib_umm_get_pyhs_addr(unsigned long addr)
{
	phys_addr_t phy_addr = (phys_addr_t)addr;

	trace_ib_exec_umm_get_pyhs_addr(addr, &phy_addr);
	return phy_addr;
}
EXPORT_SYMBOL(ib_umm_get_pyhs_addr);

void ib_device_cmdq_timeout(struct ib_device *ib_dev)
{
	trace_ib_device_exec_cmdq_timeout(ib_dev);
}
EXPORT_SYMBOL(ib_device_cmdq_timeout);
#endif

#ifdef CONFIG_DISTRIBUTED_STORAGE
bool ib_umem_is_umm_addr(unsigned long addr)
{
	struct page *page;
	int ret;

	ret = pin_user_pages_fast(addr & PAGE_MASK, 1,
		FOLL_WRITE | FOLL_LONGTERM, &page);
	if (ret < 0) {
		ofed_log_print(PANGEA_INFO,
			"Pin user page failed, addr: 0x%lx, ret: %d.", addr, ret);
		return true;
	}

	unpin_user_page(page);
	return false;
}
EXPORT_SYMBOL(ib_umem_is_umm_addr);

typedef void* (*dpumm_translate_func)(void *uaddr, u32 owner_modid, const char *owner_func);
phys_addr_t ib_umm_get_pyhs_addr(unsigned long addr)
{
	phys_addr_t paddr;

	dpumm_translate_func translate_func =
		(dpumm_translate_func)kallsyms_lookup_name_wrap("chimp_translate_uaddr_to_phyaddr");
	if (!translate_func) {
		ofed_log_print(PANGEA_ERR, "Get umm translate handler failed.");
		return (phys_addr_t)addr;
	}

	paddr = (phys_addr_t)translate_func((void *)addr, 0, __func__);
	return paddr ? paddr : (phys_addr_t)addr;
}
EXPORT_SYMBOL(ib_umm_get_pyhs_addr);
#endif
#else
#ifdef CONFIG_CENTRALIZED_STORAGE
void ib_device_cmdq_timeout(struct ib_device *ib_dev)
{
}
EXPORT_SYMBOL(ib_device_cmdq_timeout);
#endif
#endif

